"""
钉钉开放平台API测试

测试DingTalkAPI和DingTalkRobot类的功能，使用mock模拟请求，避免实际调用API。
"""

import unittest
from unittest.mock import patch, MagicMock
import json
from cn_api_adapters import DingTalkAPI, DingTalkRobot
from cn_api_adapters.common.exceptions import APIError, AuthenticationError
from cn_api_adapters.common.alibabacloud.exceptions import DingTalkError


class TestDingTalkAPI(unittest.TestCase):
    """测试DingTalkAPI类的功能"""
    
    def setUp(self):
        """设置测试环境"""
        self.app_key = "test_app_key"
        self.app_secret = "test_app_secret"
        self.api = DingTalkAPI(
            app_key=self.app_key,
            app_secret=self.app_secret,
            debug=False
        )
    
    @patch('cn_api_adapters.common.alibabacloud.dingtalk.DingTalkAPI._request')
    def test_get_access_token(self, mock_request):
        """测试获取AccessToken"""
        # 模拟成功响应
        mock_response = {
            "errcode": 0,
            "errmsg": "ok",
            "access_token": "mock_access_token",
            "expires_in": 7200
        }
        mock_request.return_value = mock_response
        
        # 获取access_token
        result = self.api.get_access_token()
        
        # 验证结果
        self.assertEqual(result, "mock_access_token")
        self.assertEqual(self.api._access_token, "mock_access_token")
        mock_request.assert_called_once_with(
            "GET",
            "https://oapi.dingtalk.com/gettoken",
            params={
                "appkey": self.app_key,
                "appsecret": self.app_secret
            }
        )
    
    @patch('cn_api_adapters.common.alibabacloud.dingtalk.DingTalkAPI._request')
    def test_get_user_info_by_code(self, mock_request):
        """测试通过code获取用户信息"""
        # 模拟access_token和成功响应
        mock_request.side_effect = [
            {"errcode": 0, "errmsg": "ok", "access_token": "mock_access_token"},
            {
                "errcode": 0,
                "errmsg": "ok",
                "userid": "test_userid",
                "deviceId": "test_device_id",
                "is_sys": False,
                "sys_level": 0
            }
        ]
        
        # 通过code获取用户信息
        code = "test_code"
        result = self.api.get_user_info_by_code(code)
        
        # 验证结果
        self.assertEqual(result["userid"], "test_userid")
        self.assertEqual(mock_request.call_count, 2)
        # 检查第二次调用参数
        mock_request.assert_called_with(
            "GET",
            "https://oapi.dingtalk.com/user/getuserinfo",
            params={
                "access_token": "mock_access_token",
                "code": code
            }
        )
    
    @patch('cn_api_adapters.common.alibabacloud.dingtalk.DingTalkAPI._request')
    def test_get_user_detail(self, mock_request):
        """测试获取用户详细信息"""
        # 模拟access_token和成功响应
        mock_request.side_effect = [
            {"errcode": 0, "errmsg": "ok", "access_token": "mock_access_token"},
            {
                "errcode": 0,
                "errmsg": "ok",
                "userid": "test_userid",
                "name": "测试用户",
                "mobile": "13800138000",
                "department": [1],
                "position": "工程师"
            }
        ]
        
        # 获取用户详细信息
        result = self.api.get_user_detail("test_userid")
        
        # 验证结果
        self.assertEqual(result["userid"], "test_userid")
        self.assertEqual(result["name"], "测试用户")
        self.assertEqual(mock_request.call_count, 2)
        # 检查第二次调用参数
        mock_request.assert_called_with(
            "GET",
            "https://oapi.dingtalk.com/user/get",
            params={
                "access_token": "mock_access_token",
                "userid": "test_userid"
            }
        )
    
    @patch('cn_api_adapters.common.alibabacloud.dingtalk.DingTalkAPI._request')
    def test_get_department_list(self, mock_request):
        """测试获取部门列表"""
        # 模拟access_token和成功响应
        mock_request.side_effect = [
            {"errcode": 0, "errmsg": "ok", "access_token": "mock_access_token"},
            {
                "errcode": 0,
                "errmsg": "ok",
                "department": [
                    {"id": 1, "name": "测试部门"}
                ]
            }
        ]
        
        # 获取部门列表
        result = self.api.get_department_list()
        
        # 验证结果
        self.assertEqual(len(result["department"]), 1)
        self.assertEqual(result["department"][0]["name"], "测试部门")
        mock_request.assert_called_with(
            "GET",
            "https://oapi.dingtalk.com/department/list",
            params={"access_token": "mock_access_token"}
        )
    
    @patch('cn_api_adapters.common.alibabacloud.dingtalk.DingTalkAPI._request')
    def test_send_work_notification(self, mock_request):
        """测试发送工作通知"""
        # 模拟access_token和成功响应
        mock_request.side_effect = [
            {"errcode": 0, "errmsg": "ok", "access_token": "mock_access_token"},
            {"errcode": 0, "errmsg": "ok", "task_id": "mock_task_id"}
        ]
        
        # 准备通知数据
        notification_data = {
            "agent_id": 123456789,
            "userid_list": "test_userid1,test_userid2",
            "msg": {
                "msgtype": "text",
                "text": {"content": "测试通知内容"}
            }
        }
        
        # 发送工作通知
        result = self.api.send_work_notification(**notification_data)
        
        # 验证结果
        self.assertEqual(result["task_id"], "mock_task_id")
        mock_request.assert_called_with(
            "POST",
            "https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2",
            params={"access_token": "mock_access_token"},
            json=notification_data
        )
    
    @patch('cn_api_adapters.common.alibabacloud.dingtalk.DingTalkAPI._request')
    def test_upload_media(self, mock_request):
        """测试上传媒体文件"""
        # 模拟access_token和成功响应
        mock_request.side_effect = [
            {"errcode": 0, "errmsg": "ok", "access_token": "mock_access_token"},
            {
                "errcode": 0,
                "errmsg": "ok",
                "media_id": "mock_media_id",
                "created_at": 1234567890
            }
        ]
        
        # 模拟媒体文件
        media_file = b"mock_file_data"
        file_name = "test.jpg"
        
        # 上传媒体文件
        result = self.api.upload_media(media_file, file_name, "image")
        
        # 验证结果
        self.assertEqual(result["media_id"], "mock_media_id")
        mock_request.assert_called_with(
            "POST",
            "https://oapi.dingtalk.com/media/upload",
            params={
                "access_token": "mock_access_token",
                "type": "image"
            },
            files={
                "media": (file_name, media_file)
            }
        )
    
    @patch('cn_api_adapters.common.alibabacloud.dingtalk.DingTalkAPI._request')
    def test_error_handling(self, mock_request):
        """测试错误处理"""
        # 模拟错误响应
        mock_request.return_value = {
            "errcode": 40001,
            "errmsg": "access_token invalid"
        }
        
        # 验证抛出DingTalkError异常
        with self.assertRaises(DingTalkError):
            self.api.get_access_token()


class TestDingTalkRobot(unittest.TestCase):
    """测试DingTalkRobot类的功能"""
    
    def setUp(self):
        """设置测试环境"""
        self.webhook = "https://oapi.dingtalk.com/robot/send?access_token=test_token"
    
    def test_initialization_with_webhook(self):
        """测试使用webhook初始化机器人"""
        robot = DingTalkRobot(webhook=self.webhook)
        self.assertEqual(robot._webhook, self.webhook)
        self.assertIsNone(robot._secret)
    
    def test_initialization_with_token_and_secret(self):
        """测试使用token和secret初始化机器人"""
        token = "test_token"
        secret = "test_secret"
        robot = DingTalkRobot(access_token=token, secret=secret)
        
        # 验证webhook和secret
        expected_webhook = f"https://oapi.dingtalk.com/robot/send?access_token={token}"
        self.assertEqual(robot._webhook, expected_webhook)
        self.assertEqual(robot._secret, secret)
    
    @patch('cn_api_adapters.common.alibabacloud.dingtalk.DingTalkRobot._request')
    def test_send_text_message(self, mock_request):
        """测试发送文本消息"""
        # 模拟成功响应
        mock_request.return_value = {"errcode": 0, "errmsg": "ok"}
        
        # 创建机器人实例
        robot = DingTalkRobot(webhook=self.webhook)
        
        # 发送文本消息
        result = robot.send_text("测试文本消息", at_mobiles=["13800138000"])
        
        # 验证结果和请求
        self.assertEqual(result, {"errcode": 0, "errmsg": "ok"})
        mock_request.assert_called_once()
        # 检查请求体中的消息内容
        call_args = mock_request.call_args
        json_data = call_args[1]["json"]
        self.assertEqual(json_data["msgtype"], "text")
        self.assertEqual(json_data["text"]["content"], "测试文本消息")
        self.assertEqual(json_data["at"]["atMobiles"], ["13800138000"])
    
    @patch('cn_api_adapters.common.alibabacloud.dingtalk.DingTalkRobot._request')
    def test_send_markdown_message(self, mock_request):
        """测试发送Markdown消息"""
        # 模拟成功响应
        mock_request.return_value = {"errcode": 0, "errmsg": "ok"}
        
        # 创建机器人实例
        robot = DingTalkRobot(webhook=self.webhook)
        
        # 发送Markdown消息
        markdown_content = "# 测试标题\n## 测试内容"
        result = robot.send_markdown("测试标题", markdown_content)
        
        # 验证结果和请求
        self.assertEqual(result, {"errcode": 0, "errmsg": "ok"})
        mock_request.assert_called_once()
        # 检查请求体中的消息内容
        call_args = mock_request.call_args
        json_data = call_args[1]["json"]
        self.assertEqual(json_data["msgtype"], "markdown")
        self.assertEqual(json_data["markdown"]["title"], "测试标题")
        self.assertEqual(json_data["markdown"]["text"], markdown_content)
    
    @patch('cn_api_adapters.common.alibabacloud.dingtalk.DingTalkRobot._request')
    def test_send_link_message(self, mock_request):
        """测试发送链接消息"""
        # 模拟成功响应
        mock_request.return_value = {"errcode": 0, "errmsg": "ok"}
        
        # 创建机器人实例
        robot = DingTalkRobot(webhook=self.webhook)
        
        # 发送链接消息
        result = robot.send_link(
            title="测试链接",
            text="链接描述",
            message_url="https://example.com",
            pic_url="https://example.com/pic.jpg"
        )
        
        # 验证结果和请求
        self.assertEqual(result, {"errcode": 0, "errmsg": "ok"})
        mock_request.assert_called_once()
        # 检查请求体中的消息内容
        call_args = mock_request.call_args
        json_data = call_args[1]["json"]
        self.assertEqual(json_data["msgtype"], "link")
        self.assertEqual(json_data["link"]["title"], "测试链接")
        self.assertEqual(json_data["link"]["messageUrl"], "https://example.com")
    
    @patch('cn_api_adapters.common.alibabacloud.dingtalk.DingTalkRobot._request')
    def test_send_action_card_message(self, mock_request):
        """测试发送ActionCard消息"""
        # 模拟成功响应
        mock_request.return_value = {"errcode": 0, "errmsg": "ok"}
        
        # 创建机器人实例
        robot = DingTalkRobot(webhook=self.webhook)
        
        # 发送ActionCard消息
        btns = [
            {"title": "按钮1", "actionURL": "https://example.com/btn1"},
            {"title": "按钮2", "actionURL": "https://example.com/btn2"}
        ]
        result = robot.send_action_card(
            title="操作卡片标题",
            text="操作卡片内容",
            btns=btns,
            btn_orientation="0"
        )
        
        # 验证结果和请求
        self.assertEqual(result, {"errcode": 0, "errmsg": "ok"})
        mock_request.assert_called_once()
        # 检查请求体中的消息内容
        call_args = mock_request.call_args
        json_data = call_args[1]["json"]
        self.assertEqual(json_data["msgtype"], "actionCard")
        self.assertEqual(json_data["actionCard"]["title"], "操作卡片标题")
        self.assertEqual(len(json_data["actionCard"]["btns"]), 2)
    
    @patch('cn_api_adapters.common.alibabacloud.dingtalk.DingTalkRobot._request')
    def test_send_feed_card_message(self, mock_request):
        """测试发送FeedCard消息"""
        # 模拟成功响应
        mock_request.return_value = {"errcode": 0, "errmsg": "ok"}
        
        # 创建机器人实例
        robot = DingTalkRobot(webhook=self.webhook)
        
        # 发送FeedCard消息
        links = [
            {
                "title": "标题1",
                "messageURL": "https://example.com/1",
                "picURL": "https://example.com/pic1.jpg"
            },
            {
                "title": "标题2",
                "messageURL": "https://example.com/2",
                "picURL": "https://example.com/pic2.jpg"
            }
        ]
        result = robot.send_feed_card(links)
        
        # 验证结果和请求
        self.assertEqual(result, {"errcode": 0, "errmsg": "ok"})
        mock_request.assert_called_once()
        # 检查请求体中的消息内容
        call_args = mock_request.call_args
        json_data = call_args[1]["json"]
        self.assertEqual(json_data["msgtype"], "feedCard")
        self.assertEqual(len(json_data["feedCard"]["links"]), 2)
    
    @patch('cn_api_adapters.common.alibabacloud.dingtalk.DingTalkRobot._request')
    def test_robot_error_handling(self, mock_request):
        """测试机器人错误处理"""
        # 模拟错误响应
        mock_request.side_effect = APIError("Robot API Error")
        
        # 创建机器人实例
        robot = DingTalkRobot(webhook=self.webhook)
        
        # 验证抛出异常
        with self.assertRaises(APIError):
            robot.send_text("测试消息")


if __name__ == '__main__':
    unittest.main()